feat(orchestration-v2): add subagent observability data model (1/5) - #4779
feat(orchestration-v2): add subagent observability data model (1/5)#4779shivamhwp wants to merge 9 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Introduces the schema, storage, and migration for richer subagent tracking. Nothing produces the new data yet — adapters populate neutral defaults so every subagent row remains valid — which keeps this change reviewable as a pure data-model step. Contracts gain a reusable subagent identity: per-activation records (SubagentActivationId, OrchestrationV2SubagentActivation), cumulative usage, a role, recent activity, and workflow grouping. A subagent may now also rest at "idle" between activations. Because a subagent status is not a turn item status, the two are bridged by an explicit mapping rather than a copy. The Record type makes that total: adding a subagent status without giving it a timeline meaning is a compile error. Without it, a producer can emit a turn item whose own schema cannot decode it, which is unrecoverable — the projection rebuild then fails on every subsequent startup and the server cannot boot. Migration 043 backfills existing rows so old events stay readable. Its riskiest path is a partially-migrated row, where already-present JSON is round-tripped through COALESCE; a test pins that structured values keep their JSON subtype rather than being rewritten as quoted strings. Also narrows event-envelope attribution in ProviderEventIngestor: a payload carrying an explicit null run or node id now keeps that null instead of inheriting the ambient run. Activations legitimately have no run id, and the envelope is persistence metadata only — routing reads payload fields — but this does change stored metadata for existing event types that already pass explicit nulls.
… backfill Every observability field the migration backfilled carries a decoding default equal to the value it wrote, so pre-upgrade rows already read back correctly without it. The projection schema version bump also fails startup verification, which deletes and replays those rows from the event log before anything reads them. Pin both halves: a contracts test decodes a stored payload missing all eight fields through the schema the projection actually uses, and the migration test asserts an existing row survives byte-identical. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cope The lint rule the CI Check job enforces flags a compiled decoder rebuilt on every call. The activation payload decoder and the subagent decoders this PR added were inline, which took the branch from the base's 67 lint warnings to 73 and failed the job. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
f4037f3 to
e4f6d13
Compare
…o stack-01 # Conflicts: # apps/server/src/orchestration-v2/ProviderEventIngestor.test.ts # apps/server/src/persistence/Migrations.ts # apps/server/src/persistence/Migrations/036_037_OrchestrationV2.test.ts
…runs Promoting a queued run rewrote its user_message turn item with inputIntent: "turn_start", clobbering the queued_turn intent the item was created with. Every provider's queued_turn replay fixture failed with [turn_start, turn_start] instead of [turn_start, queued_turn]. Keep the existing item's intent and only default the synthesized fallback, which is queued by definition. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ApprovabilityVerdict: Needs human review New feature adding subagent observability data model with schema changes, new database migration, new event types, and runtime modifications in the orchestrator. The scope and nature of these changes warrant human review. You can customize Macroscope's approvability policy. Learn more. |
…o stack-01 # Conflicts: # apps/server/src/orchestration-v2/Orchestrator.ts
First of five stacked PRs replacing #4551, which bundled the whole subagent-observability feature into one ~3,100-line change. Splitting it out so each piece can actually be reviewed; the seams between these pieces are where the bugs were hiding.
Scope: data model, storage, and migration only. Nothing produces the new data yet. Adapters are given neutral defaults so every subagent row stays valid. Populating them for real is 2/5, and reuse semantics are 3/5.
What's here
Contracts gain a reusable subagent identity — per-activation records (
SubagentActivationId,OrchestrationV2SubagentActivation), cumulative usage, a role, recent activity, and workflow grouping. A subagent can also now rest atidlebetween activations.Migration 044 creates the activation projection table. Legacy rows stay readable through schema defaults and projection replay, so no JSON backfill is required.
The status mapping is the important part
A subagent status is not a turn item status —
idlehas no timeline equivalent. The two are bridged by an explicitRecord<subagent status, turn item status>rather than a copy, which makes the mapping total: adding a subagent status without giving it a timeline meaning is a compile error.This is not hypothetical. An earlier iteration copied the raw status through, which wrote a
turn-item.updatedevent that its own schema could not decode. Nothing failed at write time — but the projection rebuild runs at startup and died on that stored event, so the server became permanently unbootable with no in-app recovery. Addingidlein this PR immediately trips the new compile error atCodexAdapterV2.ts, which is the guard doing its job.Notes for review
ProviderEventIngestorno longer replaces an explicit nullrunId/nodeIdwith the ambient run. Activations legitimately have no run id. The envelope is persistence metadata only (routing reads payload fields), but this does change stored metadata for existing event types that already pass explicit nulls.idle. Only relevant if that build ran anywhere beyond local dev.Testing
Typecheck clean and lint clean across server, contracts, client-runtime, and web.
Also booted a server on a fresh state directory and confirmed migration 044 applies and the app starts.
Reviewed by an independent agent pass before opening; its findings on helper scope and the missing mixed-row migration test are folded in.
Note
Medium Risk
Touches orchestration event persistence, projection schema version (forced rebuild), and envelope attribution for null run/node ids; delegated-task paths now emit activation events. Adapters still use defaults rather than full provider observability, limiting runtime behavior change in this slice.
Overview
Adds a reusable subagent identity model with per-activation records, usage/role/activity/workflow fields on subagents, and a new
idleresting status between activations. Contracts introduceSubagentActivationId,OrchestrationV2SubagentActivation, thesubagent-activation.updateddomain event, andsubagentActivationson thread projections—with schema defaults so legacy stored subagent JSON still decodes.Persistence: migration 045 creates
orchestration_v2_projection_subagent_activations(no JSON backfill of existing subagent rows). Projection schema version bumps 2 → 3; rebuild/maintenance clears activation rows and replays from the event log.Pipeline wiring:
ProjectionStore, client-runtime projection,ProviderEventIngestor(mapssubagent_activation.updated→ domain event), andRunExecutionServicerouting.ProviderEventIngestorno longer overwrites enveloperunId/nodeIdwhen the payload explicitly passesnull(needed for detached activations).Producers (still mostly defaults): provider adapters and tests populate neutral observability defaults on subagent payloads; Codex maps subagent status to turn-item status via
orchestrationV2SubagentStatusAsTurnItemStatus(idle→completed).Orchestratoremits activation events when app-owned delegated tasks start and when they terminalize. Shared helpers live inSubagentObservability.ts.A compile-time
Recordmaps every subagent status to a decodable turn-item status so rawidlecannot be copied onto timeline rows and brick projection replay.Reviewed by Cursor Bugbot for commit 9d3c4c6. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add subagent activation observability data model to orchestration-v2
OrchestrationV2SubagentActivationas a first-class schema inorchestrationV2.ts, with a newsubagent-activation.updateddomain event and thread projection fieldsubagentActivations.OrchestrationV2Subagent:kind,role,usage,currentActivationId,activationCount,workflow,workflowMembership, andrecentActivity, all with backward-compatible defaults.subagent-activation.updatedevents when delegating work (running state) and on termination, tracking activation lifecycle inOrchestrator.ts.045_OrchestrationV2SubagentObservability.ts) creating theorchestration_v2_projection_subagent_activationstable with indexes on(thread_id, subagent_id, ordinal)and(run_id, status).Macroscope summarized 9d3c4c6.